#pragma once

#include <engine.core/api_exception.hpp>




typedef boost::error_info<struct tag_d3d11_hresult,HRESULT>     d3d11_result;




class d3d11_exception : public api_exception
{
public:

	d3d11_exception(const std::string& what) : api_exception(what) {}

	HRESULT getAPIResult() const
	{
		if(const HRESULT* err = boost::get_error_info<d3d11_result>(*this))
			return *err;
		else
			return D3D_OK;
	}



	/**
	 * Verifies the given result from a D3D11 API call and throws an exception in case the it failed.
	 */
	static void verify_call(HRESULT hr, const char* call, const char* file, const char* function, int line)
	{
		if(FAILED(hr))
		{
			throw d3d11_exception(format("A D3D11 API call failed: %1%(%2%)") % readableResult(hr) % hr)
				<< debug_info_m(file, function, line)
				<< d3d11_result(hr)
				<< api_call(call)
			;
		}
	}



	/**
	 * This function returns a readable result string for the given HRESULT.
	 * Currently, all DXGI error codes are known
	 */
	static const char* readableResult(HRESULT hr)
	{
		switch(hr)
		{
		case DXGI_ERROR_DEVICE_HUNG:  return __STR__(DXGI_ERROR_DEVICE_HUNG);
		case DXGI_ERROR_DEVICE_REMOVED: return __STR__(DXGI_ERROR_DEVICE_REMOVED);
		case DXGI_ERROR_DEVICE_RESET: return __STR__(DXGI_ERROR_DEVICE_RESET);
		case DXGI_ERROR_DRIVER_INTERNAL_ERROR: return __STR__(DXGI_ERROR_DRIVER_INTERNAL_ERROR);
		case DXGI_ERROR_FRAME_STATISTICS_DISJOINT: return __STR__(DXGI_ERROR_FRAME_STATISTICS_DISJOINT);
		case DXGI_ERROR_GRAPHICS_VIDPN_SOURCE_IN_USE: return __STR__(DXGI_ERROR_GRAPHICS_VIDPN_SOURCE_IN_USE);
		case DXGI_ERROR_INVALID_CALL: return __STR__(DXGI_ERROR_INVALID_CALL);
		case DXGI_ERROR_MORE_DATA: return __STR__(DXGI_ERROR_MORE_DATA);
		case DXGI_ERROR_NONEXCLUSIVE: return __STR__(DXGI_ERROR_NONEXCLUSIVE);
		case DXGI_ERROR_NOT_CURRENTLY_AVAILABLE: return __STR__(DXGI_ERROR_NOT_CURRENTLY_AVAILABLE);
		case DXGI_ERROR_NOT_FOUND: return __STR__(DXGI_ERROR_NOT_FOUND);
		case DXGI_ERROR_REMOTE_CLIENT_DISCONNECTED: return __STR__(DXGI_ERROR_REMOTE_CLIENT_DISCONNECTED);
		case DXGI_ERROR_REMOTE_OUTOFMEMORY: return __STR__(DXGI_ERROR_REMOTE_OUTOFMEMORY);
		case DXGI_ERROR_WAS_STILL_DRAWING: return __STR__(DXGI_ERROR_WAS_STILL_DRAWING);
		case DXGI_ERROR_UNSUPPORTED: return __STR__(DXGI_ERROR_UNSUPPORTED);
		case S_OK: return __STR__(S_OK);
		default: return "Unknown hresult";
		}
	}
};
///////////////////////////////////////////////////////////////////////////////////////////////////

/**
 * This macro executes the given D3D11 call and tests if it returned an error code.
 * (Tested via the FAILED macro from Microsoft).
 */
#define D3D11_API(x) d3d11_exception::verify_call((x), #x, __FILE__, __FUNCTION__, __LINE__)

/**
 * This macro does not execute the call, but still verifies the result.
 * It helps when certain error codes should not trigger an exception, but
 * others should (without the need to write much code.
 *
 * Usage:
 *  HRESULT hr = m_device->reset();
 *  if(hr == DXGI_ERROR_DEVICE_RESET) // DO something
 *  else D3D11_API_F(hr, m_device->reset());
 */
#define D3D11_API_F(hr, x) d3d11_exception::verify_call(hr, #x, __FILE__, __FUNCTION__, __LINE__)
